package com.miyu.common.utils.redis.redisUtils;



import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.miyu.common.utils.redis.redisUtils.util.RedisBaseUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * redis缓存工具类
 * @author longm
 * @date 2022/11/20
 */
@ConditionalOnBean(RedisBaseUtil.class)
public class RedisCache extends RedisBaseUtil{


    /**
     * 获取当前文件加下所有keys
     * @param redisKey redis键
     * @return {@link Set}<{@link String}>
     */
    public Set<String> getKeys(String redisKey) {
        return getKeys(0,redisKey);
    }
   public Set<String> getKeys(int dbIndex ,String redisKey){
       Set<Object> keys = knife4jRedisManager.redisTemplate(0).keys(redisKey+":**");
       Set<String> retKeys = new HashSet<>();
        for (Object key : keys) {
        retKeys.add(String.valueOf(key));
        }
        return retKeys;
    }
    /**
     * 在list集合最前面插入数据
     * @param key  需要操作的key.
     * @param values 待添加的值
     * @return
     */
    public Long insert(String key, Object ... values) {
        return insert(defaultDB ,key , values);
    }

    /**
     * 在list集合最前面插入数据

     * @param key     关键
     * @param values  值
     * @return {@link Long}
     */
    public Long insert(int dbIndex ,String key, Object ... values) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPushAll(key, values);
    }

    /**
     * 在list集合最前面插入数据
     * 带有有效时间设置
     * @param key     关键
     * @param timeout 超时
     * @param values  值
     * @return {@link Long}
     */
    public Long insert(String key,long timeout, Object ... values) {
        return knife4jRedisManager.redisTemplate(defaultDB).opsForList().leftPushAll(key, values,timeout,TimeUnit.SECONDS);
    }
    public Long insert(int dbIndex ,String key,long timeout, Object ... values) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPushAll(key, values,timeout,TimeUnit.SECONDS);
    }

    /**
     * 在list集合最前面插入数据
     * @param key    关键
     * @param values 值
     * @return {@link Long}
     */
    public Long insert(String key, Collection<?>... values) {
        return insert(defaultDB , key ,values);
    }

    /**
     * 在list集合最前面插入数据
     * @param dbIndex 数据库索引
     * @param key     关键
     * @param values  值
     * @return {@link Long}
     */
    public Long insert(int dbIndex ,String key, Collection<?>... values) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPushAll(key ,values);
    }

    /**
     * 在list集合最前面插入数据
     * 带有有效时间设置
     * @param key     关键
     * @param timeout 超时
     * @param values  值
     * @return {@link Long}
     */
    public Long insert(String key,long timeout, Collection<?>... values) {
        return knife4jRedisManager.redisTemplate(defaultDB).opsForList().leftPushAll(key ,values,timeout,TimeUnit.SECONDS);
    }
    public Long insert(int dbIndex ,String key,long timeout, Collection<?>... values) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPushAll(key ,values,timeout,TimeUnit.SECONDS);
    }
    /**
     * 在list集合最后面追加数据
     * @param key  需要操作的key
     * @param values 待添加的值
     * @return
     */
    public Long append(String key, Object... values) {
        return append(defaultDB , key , values);
    }

    /**
     * 在list集合最后面追加数据
     * @param dbIndex 数据库索引
     * @param key     关键
     * @param values  值
     * @return {@link Long}
     */
    public Long append(int dbIndex ,String key, Object... values) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().rightPushAll(key, values);
    }

    /**
     * 在list集合最后面追加数据
     * 带有有效时间设置
     * @param dbIndex 数据库索引
     * @param key     关键
     * @param timeout 超时
     * @param values  值
     * @return {@link Long}
     */
    public Long append(int dbIndex ,String key,long timeout, Object... values) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().rightPushAll(key, values);
    }
    /**
     * 在指定索引处添加数据，如果存在则为替换
     * @param key 需要操作的key
     * @param index 指定索引，该索引从0开始
     * @param value 待添加的值
     */
    public void setList(String key, long index, Object value) {
        setList(defaultDB , key ,index,value);
    }
    public void setList(int dbIndex ,String key, long index, Object value) {
        knife4jRedisManager.redisTemplate(dbIndex).opsForList().set(key , index ,value);
    }
    /**
     * 取出某个范围的集合数据
     * @param key 需要操作的key
     * @param start 集合起点，索引从0开始
     * @param end 集合终点，若为-1则表示取出所有
     * @return 返回所有对象
     */
    public <T> List<T> getList(String key, long start, long end , Class<T> t) {
        return getList(defaultDB , key , start , end , t);
    }
    public <T> List<T> getList(int dbIndex ,String key, long start, long end , Class<T> t) {
        //此处返回的真实类型是JSONArray
        List<Object> list = knife4jRedisManager.redisTemplate(dbIndex).opsForList().range(key, start, end);
        List<T> ts = (List<T>) JSONArray.parse(String.valueOf(list), JSONReader.Feature.IgnoreSetNullValue);
        return ts;
    }
    /**
     * 获取redis集合类型所有元素
     * @param key
     * @param t
     * @param <T>
     * @return
     */
    public <T> List<T> getListAll(String key , Class<T> t) {
        return getListAll(defaultDB , key , t);
    }
    public <T> List<T> getListAll(int dbIndex ,String key , Class<T> t) {
        List<Object> list = knife4jRedisManager.redisTemplate(dbIndex).opsForList().range(key, 0, -1);
        List<T> ts = (List<T>) JSONArray.parse(String.valueOf(list), JSONReader.Feature.IgnoreSetNullValue);
        return ts;
    }
    /**
     * 返回list集合的大小
     * @param key 需要操作的key
     * @return
     */
    public Long size(String key) {
        return size(defaultDB , key);
    }
    public Long size(int dbIndex ,String key) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().size(key);
    }

    /**
     * 返回某个索引处的数据
     * @param key  需要操作的key
     * @param index 索引 下标从0开始
     * @return
     */
    public <T> T getByIndex(String key , long index , Class<T> clazz) {
        return getByIndex(defaultDB , key , index , clazz);
    }
    public <T> T getByIndex(int dbIndex ,String key , long index , Class<T> clazz) {
        Object obj = knife4jRedisManager.redisTemplate(dbIndex).opsForList().index(key, index);
        return JSONObject.parseObject(String.valueOf(obj) , clazz);
    }

    /**
     * 弹出最左边数据，弹出后集合将不存在该数据
     * @param key
     * @return
     */
    public <T> T popLeft(String key , Class<T> clazz) {
        return  popLeft(defaultDB , key , clazz);
    }
    public <T> T popLeft(int dbIndex ,String key , Class<T> clazz) {
        Object obj = knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPop(key);
        if(obj == null){
            return null;
        }
        return JSONObject.parseObject(String.valueOf(obj) , clazz);
    }
    /**
     * 弹出最右边数据，弹出后集合将不存在该数据
     * @param key
     * @return
     */
    public <T> T  popRight(String key , Class<T> clazz) {
        return popRight(defaultDB , key , clazz);
    }
    public <T> T  popRight(int dbIndex ,String key , Class<T> clazz) {
        Object obj = knife4jRedisManager.redisTemplate(dbIndex).opsForList().rightPop(key);
        if(obj == null){
            return null;
        }
        return JSONObject.parseObject(String.valueOf(obj) , clazz);
    }
    /**
     * 直接删除数据，该数据从某个位置开始
     * @param key   删除的key
     * @param count
     *          大于0，表示删除从左往右数，值为value的第一个数据
     *          小于0，表示删除从右往左数，值为value的第一个数据
     *          等于0，表示删除值为value的所有数据
     * @param value 被删除的数据
     * @return
     */
    public Long remove(String key, long count, Object value) {
        return remove(defaultDB , key , count , value);
    }
    public Long remove(int dbIndex ,String key, long count, Object value) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().remove(key, count , value);
    }

    /**
     * redis删除某个key值
     * @param key 钥匙
     */
    public void remove(String key) {
        delete(0,key);
    }
    public void remove(int dbIndex ,String key) {
        knife4jRedisManager.redisTemplate(dbIndex).delete(key);
    }

    /**
     * 普通缓存放入
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    @Override
    public boolean set(String key, Object value) {
        return  set(defaultDB , key ,value);
    }
    @Override
    public boolean set(int dbIndex , String key, Object value) {
        try {
            if(knife4jRedisManager.isEnableRedis(dbIndex)) {
                knife4jRedisManager.redisTemplate(dbIndex).opsForValue().set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取 String 类型 key-value
     * @param key 键
     * @return {@link String}
     */
    public String get(String key) {
        return get(defaultDB ,key);
    }
    public String get(int dbIndex ,String key) {
        Object result =null;
        if(knife4jRedisManager.isEnableRedis(dbIndex)) {
            result= knife4jRedisManager.redisTemplate(dbIndex).opsForValue().get(key);
        }
        return result == null ? null : String.valueOf(result) ;
    }

    /**
     * 获取单对象 redis<String,Clazz>
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T get(String key , Class<T> clazz) {
        return  get(defaultDB ,key , clazz);
    }
    public <T> T get(int dbIndex ,String key , Class<T> clazz) {
        Object o=null;
        if(knife4jRedisManager.isEnableRedis(dbIndex)) {
            o = knife4jRedisManager.redisTemplate(dbIndex).opsForValue().get(key);
        }
        if(o instanceof JSONObject){
            T t = ((JSONObject) o).to(clazz);
            return t;
        }
        T t = ((JSONObject) o).to(clazz);
        return t;
    }

    /**
     *
     * 带失效时间设置
     * @param key     键
     * @param value   值
     * @param timeout 失效时间（秒）
     */
    public void set(String key, Object value, long timeout) {
        set(defaultDB , key ,value ,timeout);
    }
    public void set(int dbIndex ,String key, Object value, long timeout) {
        if(knife4jRedisManager.isEnableRedis(dbIndex)) {
            knife4jRedisManager.redisTemplate(dbIndex).opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
        }
    }

    /**
     * 为多个键分别设置他们的值
     * 使用：Map<String,String> maps = new HashMap<String, String>();
     * maps.put("multi1","ccc");
     * maps.put("multi2","xxx");
     * maps.put("multi3","zzz");
     * template.opsForValue().multiSet(maps);
     *
     * @param map
     */
    protected void multiSetObj(Map<String, Object> map) {
        multiSetObj(defaultDB , map);
    }
    protected void multiSetObj(int dbIndex ,Map<String, Object> map) {
        if(knife4jRedisManager.isEnableRedis(dbIndex)) {
            knife4jRedisManager.redisTemplate(dbIndex).opsForValue().multiSet(map);
        }
    }

    /***
     * 分多个键同时取出他们的值
     * List<String> keys = new ArrayList<String>();
     keys.add("multi1");
     keys.add("multi2");
     keys.add("multi3");
     System.out.println(template.opsForValue().multiGet(keys));
     结果：[ccc, xxx, zzz]
     * @param keys
     *
     */
    protected List<Object> multiGetObj(List<String> keys) {
        return multiGetObj(defaultDB ,keys);
    }
    protected List<Object> multiGetObj(int dbIndex ,List<String> keys) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().multiGet(keys);
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        return incr(defaultDB , key , delta);
    }
    public long incr(int dbIndex ,String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().increment(key, delta);
    }

    public long incrFiled(String key, String filed) {
        return incrFiled(defaultDB , key , filed);
    }
    public long incrFiled(int dbIndex ,String key, String filed) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForHash().increment(key, filed, 1);
    }
    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        return decr(defaultDB , key ,delta);
    }
    public long decr(int dbIndex ,String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().increment(key, -delta);
    }

    //存hash
    public void setHash(String key, String filed, String value) {
        setHash(defaultDB ,key , filed ,value);
    }
    public void setHash(int dbIndex ,String key, String filed, String value) {
        knife4jRedisManager.redisTemplate(dbIndex).opsForHash().put(key, filed, value);
    }

    //取hash
    public String getHash(String key, String filed) {
        return getHash(defaultDB ,key ,filed);
    }
    public String getHash(int dbIndex ,String key, String filed) {
        Object o = knife4jRedisManager.redisTemplate(dbIndex).opsForHash().get(key, filed);
        return (String) o;
    }

    public void setList(String key, List<String> list) {
        setList(defaultDB , key , list);
    }
    public void setList(int dbIndex ,String key, List<String> list) {
        knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPush(key, list);
    }

    public List<String> getList(String key) {
        return getList(defaultDB ,key);
    }
    public List<String> getList(int dbIndex ,String key) {
        return (List<String>) knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPop(key);
    }

    public void lPush(String key, String value){
        lPush(defaultDB , key , value);
    }
    public void lPush(int dbIndex ,String key, String value){
        knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPush(key, value);
    }

    public String lPop(String key){
        return lPop(defaultDB ,key);
    }
    public String lPop(int dbIndex ,String key){
        return (String) knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPop(key);
    }

    public Long listSize(String key){
        return listSize(defaultDB , key);
    }
    public Long listSize(int dbIndex ,String key){
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().size(key);
    }

    /**
     * 查询list中指定范围的内容
     * @param key 关键
     * @return {@link List}<{@link String}>
     */
    public List<String> range(String key){
        return range(defaultDB , key);
    }
    public List<String> range(int dbIndex ,String key){
        List<Object> range = knife4jRedisManager.redisTemplate(dbIndex).opsForList().range(key, 0, -1);
        List<String> result = new ArrayList<>();
        for (Object o : range) {
            result.add((String)o);
        }
        return result;
    }

    /**
     * 查询key 有效期
     * @param key 关键
     * @return {@link Long}
     */
    public Long ttl(String key) {
        return ttl(defaultDB , key);
    }
    public Long ttl(int dbIndex ,String key) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().getOperations().getExpire(key);
    }
}
